# -*- coding: utf-8 -*-
"""
数据库连接配置

功能说明:
- MongoDB连接管理
- Redis连接管理
- 数据库初始化
- 连接池配置
- 健康检查

作者: MetasoCreator Team
创建时间: 2025-08-19
"""

import os
import logging
from typing import Optional, Dict, Any
from pymongo import MongoClient
from pymongo.database import Database
from pymongo.collection import Collection
from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError
import redis
from redis.exceptions import ConnectionError as RedisConnectionError
from flask import current_app

# 配置日志
logger = logging.getLogger(__name__)


class MongoDBManager:
    """MongoDB连接管理器"""
    
    def __init__(self):
        self._client: Optional[MongoClient] = None
        self._database: Optional[Database] = None
        self._collections: Dict[str, Collection] = {}
    
    def init_app(self, app):
        """初始化Flask应用"""
        self.app = app
        self._setup_connection()
    
    def _setup_connection(self):
        """建立MongoDB连接"""
        try:
            # 从配置获取连接参数
            mongo_uri = current_app.config.get('MONGO_URI')
            database_name = current_app.config.get('MONGO_DATABASE', 'metaso_creator')
            
            if not mongo_uri:
                logger.error("MongoDB URI未配置")
                return
            
            # 创建MongoDB客户端
            self._client = MongoClient(
                mongo_uri,
                serverSelectionTimeoutMS=5000,  # 5秒超时
                connectTimeoutMS=10000,         # 10秒连接超时
                socketTimeoutMS=20000,          # 20秒socket超时
                maxPoolSize=50,                 # 最大连接池大小
                minPoolSize=5,                  # 最小连接池大小
                maxIdleTimeMS=30000,           # 最大空闲时间30秒
                waitQueueTimeoutMS=5000,       # 等待队列超时5秒
            )
            
            # 获取数据库
            self._database = self._client[database_name]
            
            # 测试连接
            self._client.admin.command('ping')
            logger.info(f"MongoDB连接成功: {database_name}")
            
            # 初始化集合
            self._init_collections()
            
        except (ConnectionFailure, ServerSelectionTimeoutError) as e:
            logger.error(f"MongoDB连接失败: {e}")
            self._client = None
            self._database = None
        except Exception as e:
            logger.error(f"MongoDB初始化异常: {e}")
            self._client = None
            self._database = None
    
    def _init_collections(self):
        """初始化集合"""
        if not self._database:
            return
        
        # 定义集合名称
        collection_names = [
            'search_history',    # 搜索历史
            'user_profiles',     # 用户档案
            'search_results',    # 搜索结果缓存
            'api_logs',         # API调用日志
            'system_configs',   # 系统配置
        ]
        
        # 创建集合引用
        for name in collection_names:
            self._collections[name] = self._database[name]
        
        # 创建索引
        self._create_indexes()
        
        logger.info(f"MongoDB集合初始化完成: {list(self._collections.keys())}")
    
    def _create_indexes(self):
        """创建数据库索引"""
        try:
            # 搜索历史索引
            search_history = self._collections.get('search_history')
            if search_history:
                search_history.create_index([('user_id', 1), ('created_at', -1)])
                search_history.create_index([('query', 'text')])
                search_history.create_index([('status', 1)])
            
            # 用户档案索引
            user_profiles = self._collections.get('user_profiles')
            if user_profiles:
                user_profiles.create_index([('user_id', 1)], unique=True)
                user_profiles.create_index([('email', 1)], unique=True, sparse=True)
                user_profiles.create_index([('created_at', -1)])
            
            # 搜索结果缓存索引
            search_results = self._collections.get('search_results')
            if search_results:
                search_results.create_index([('query_hash', 1)])
                search_results.create_index([('created_at', 1)], expireAfterSeconds=3600)  # 1小时过期
            
            # API日志索引
            api_logs = self._collections.get('api_logs')
            if api_logs:
                api_logs.create_index([('timestamp', -1)])
                api_logs.create_index([('endpoint', 1)])
                api_logs.create_index([('user_id', 1)])
                api_logs.create_index([('created_at', 1)], expireAfterSeconds=2592000)  # 30天过期
            
            logger.info("MongoDB索引创建完成")
            
        except Exception as e:
            logger.error(f"创建MongoDB索引失败: {e}")
    
    def get_collection(self, name: str) -> Optional[Collection]:
        """获取集合"""
        return self._collections.get(name)
    
    def get_database(self) -> Optional[Database]:
        """获取数据库"""
        return self._database
    
    def get_client(self) -> Optional[MongoClient]:
        """获取客户端"""
        return self._client
    
    def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        try:
            if not self._client:
                return {'status': 'error', 'message': 'MongoDB客户端未初始化'}
            
            # 执行ping命令
            result = self._client.admin.command('ping')
            
            # 获取服务器状态
            server_status = self._client.admin.command('serverStatus')
            
            return {
                'status': 'healthy',
                'ping': result.get('ok', 0) == 1,
                'version': server_status.get('version', 'unknown'),
                'uptime': server_status.get('uptime', 0),
                'connections': server_status.get('connections', {}),
                'database': self._database.name if self._database else None,
                'collections': list(self._collections.keys())
            }
            
        except Exception as e:
            return {
                'status': 'error',
                'message': f'MongoDB健康检查失败: {str(e)}'
            }
    
    def close(self):
        """关闭连接"""
        if self._client:
            self._client.close()
            logger.info("MongoDB连接已关闭")


class RedisManager:
    """Redis连接管理器"""
    
    def __init__(self):
        self._client: Optional[redis.Redis] = None
        self._connection_pool: Optional[redis.ConnectionPool] = None
    
    def init_app(self, app):
        """初始化Flask应用"""
        self.app = app
        self._setup_connection()
    
    def _setup_connection(self):
        """建立Redis连接"""
        try:
            # 从配置获取连接参数
            redis_url = current_app.config.get('REDIS_URL')
            
            if not redis_url:
                logger.error("Redis URL未配置")
                return
            
            # 创建连接池
            self._connection_pool = redis.ConnectionPool.from_url(
                redis_url,
                max_connections=20,      # 最大连接数
                retry_on_timeout=True,   # 超时重试
                socket_timeout=5,        # socket超时5秒
                socket_connect_timeout=5, # 连接超时5秒
                health_check_interval=30, # 健康检查间隔30秒
            )
            
            # 创建Redis客户端
            self._client = redis.Redis(
                connection_pool=self._connection_pool,
                decode_responses=True,   # 自动解码响应
                encoding='utf-8'
            )
            
            # 测试连接
            self._client.ping()
            logger.info("Redis连接成功")
            
        except RedisConnectionError as e:
            logger.error(f"Redis连接失败: {e}")
            self._client = None
            self._connection_pool = None
        except Exception as e:
            logger.error(f"Redis初始化异常: {e}")
            self._client = None
            self._connection_pool = None
    
    def get_client(self) -> Optional[redis.Redis]:
        """获取Redis客户端"""
        return self._client
    
    def set(self, key: str, value: Any, ex: Optional[int] = None) -> bool:
        """设置键值"""
        try:
            if not self._client:
                return False
            
            return self._client.set(key, value, ex=ex)
        except Exception as e:
            logger.error(f"Redis设置失败: {e}")
            return False
    
    def get(self, key: str) -> Optional[str]:
        """获取值"""
        try:
            if not self._client:
                return None
            
            return self._client.get(key)
        except Exception as e:
            logger.error(f"Redis获取失败: {e}")
            return None
    
    def delete(self, *keys: str) -> int:
        """删除键"""
        try:
            if not self._client:
                return 0
            
            return self._client.delete(*keys)
        except Exception as e:
            logger.error(f"Redis删除失败: {e}")
            return 0
    
    def exists(self, key: str) -> bool:
        """检查键是否存在"""
        try:
            if not self._client:
                return False
            
            return self._client.exists(key) > 0
        except Exception as e:
            logger.error(f"Redis检查存在失败: {e}")
            return False
    
    def expire(self, key: str, time: int) -> bool:
        """设置过期时间"""
        try:
            if not self._client:
                return False
            
            return self._client.expire(key, time)
        except Exception as e:
            logger.error(f"Redis设置过期时间失败: {e}")
            return False
    
    def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        try:
            if not self._client:
                return {'status': 'error', 'message': 'Redis客户端未初始化'}
            
            # 执行ping命令
            ping_result = self._client.ping()
            
            # 获取Redis信息
            info = self._client.info()
            
            return {
                'status': 'healthy',
                'ping': ping_result,
                'version': info.get('redis_version', 'unknown'),
                'uptime': info.get('uptime_in_seconds', 0),
                'connected_clients': info.get('connected_clients', 0),
                'used_memory': info.get('used_memory_human', '0B'),
                'total_commands_processed': info.get('total_commands_processed', 0)
            }
            
        except Exception as e:
            return {
                'status': 'error',
                'message': f'Redis健康检查失败: {str(e)}'
            }
    
    def close(self):
        """关闭连接"""
        if self._connection_pool:
            self._connection_pool.disconnect()
            logger.info("Redis连接已关闭")


# 全局实例
mongo_manager = MongoDBManager()
redis_manager = RedisManager()


def init_databases(app):
    """初始化数据库连接"""
    logger.info("开始初始化数据库连接...")
    
    # 初始化MongoDB
    mongo_manager.init_app(app)
    
    # 初始化Redis
    redis_manager.init_app(app)
    
    logger.info("数据库连接初始化完成")


def get_mongo_collection(name: str) -> Optional[Collection]:
    """获取MongoDB集合"""
    return mongo_manager.get_collection(name)


def get_mongo_database() -> Optional[Database]:
    """获取MongoDB数据库"""
    return mongo_manager.get_database()


def get_redis_client() -> Optional[redis.Redis]:
    """获取Redis客户端"""
    return redis_manager.get_client()


def database_health_check() -> Dict[str, Any]:
    """数据库健康检查"""
    return {
        'mongodb': mongo_manager.health_check(),
        'redis': redis_manager.health_check()
    }


def close_databases():
    """关闭数据库连接"""
    mongo_manager.close()
    redis_manager.close()
    logger.info("所有数据库连接已关闭")